﻿using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Reference.Apps.Models.Data;
using Reference.Apps.Models.Entities;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Windows.ApplicationModel.DataTransfer;

namespace Reference.Apps.ViewModels
{
    public class MainPageViewModel : ViewModelBase
    {

        private ReferenceWebService webService;
        private Reference.Apps.Common.StorageHelper storage;
        private int codeFontIndex;
        private double[] fontSizes;
        public MainPageViewModel()
        {
#if WINDOWS_APP
            fontSizes = new double[] { 18, 20, 21.333, 23, 25 };
            codeFontIndex = 2;
            CodeFontSize = 21.333;
#else
            fontSizes = new double[] { 10, 12, 14.667, 16, 18 };
            codeFontIndex = 2;
            CodeFontSize = 14.667;
#endif
            #region DesignMode
            if (IsInDesignMode)
            {
                Groups = new ObservableCollection<CodeGroup>();
                for (int i = 0; i < 6; i++)
                {
                    ObservableCollection<CodeSnippet> nSnippets = new ObservableCollection<CodeSnippet>();
                    for (int ii = 0; ii < 10; ii++)
                    {
                        nSnippets.Add(new CodeSnippet
                        {
                            Title = "CodeSnippet " + ii,
                            CodeGroupName = "Groups " + i,
                            Notes = "Notes from " + i + " to " + ii,
                            Lang = ii + i % 3 == 0 ? "java" : ii + i % 3 == 1 ? "cpp" : "cs",
                            Code = "#include <deque>\ndeque<T> D      // O(1)\nD.push_back(T)  // O(1)\nD.push_front(T) // O(1)\nD.pop_back()    // O(1)\nD.pop_front()   // O(1)\nD.size()        // O(1)\nD.back()        // O(1)\nD.front()       // O(1)\nD.clear()       // O(n)"
                        });
                    }
                    Groups.Add(new CodeGroup
                    {
                        GroupId = i,
                        Name = "Groups" + i,
                        Snippets = nSnippets
                    });
                }
                CodeViewSnippet = groups[0].Snippets[0];
                SelectedCodeGroup = groups[0];
                SearchResults = groups[0].Snippets;
                SearchTerm = "My search term";

            }
            else
            {
                webService = new ReferenceWebService();
                storage = new Reference.Apps.Common.StorageHelper();
                IsFirstTimeLoaded = true;
            }
            #endregion
        }

        #region Exposed properties
        private double codeFontSize;

        public double CodeFontSize
        {
            get { return codeFontSize; }
            set { codeFontSize = value; RaisePropertyChanged(); }
        }


        private bool isBusy;

        public bool IsBusy
        {
            get { return isBusy; }
            set { isBusy = value; RaisePropertyChanged(); }
        }

        public bool IsFirstTimeLoaded { get; set; }

        private ObservableCollection<CodeGroup> groups;
        public ObservableCollection<CodeGroup> Groups
        {
            get { return groups; }
            set { groups = value; RaisePropertyChanged(); }
        }

        private CodeSnippet codeViewSnippet;

        public CodeSnippet CodeViewSnippet
        {
            get { return codeViewSnippet; }
            set { codeViewSnippet = value; RaisePropertyChanged(); }
        }

        private CodeGroup selectedCodeGroup;

        public CodeGroup SelectedCodeGroup
        {
            get { return selectedCodeGroup; }
            set { selectedCodeGroup = value; RaisePropertyChanged(); }
        }


        private string searchTerm;
        public string SearchTerm
        {
            get { return searchTerm; }
            set { searchTerm = value; RaisePropertyChanged(); if (searchCommand != null)searchCommand.RaiseCanExecuteChanged(); }
        }

        private ObservableCollection<CodeSnippet> results;
        public ObservableCollection<CodeSnippet> SearchResults
        {
            get { return results; }
            set { results = value; RaisePropertyChanged(); }
        }

        #endregion

        #region Commands
        private RelayCommand getCodeViewCommand;
        public RelayCommand GetCodeViewCommand
        {
            get
            {
                return getCodeViewCommand ?? (getCodeViewCommand = new RelayCommand(() =>
                {
                    IsBusy = true;
                    GetCodeViewSnippet();
                }));
            }
        }

        private RelayCommand updateDataCommand;
        public RelayCommand UpdateDataCommand
        {
            get
            {
                return updateDataCommand ?? (updateDataCommand = new RelayCommand(() =>
                {
                    IsBusy = true;
                    GetGroupsFromWebService();
                }));
            }
        }

        private RelayCommand getDataCommand;
        public RelayCommand GetDataCommand
        {
            get
            {
                if (getDataCommand == null)
                    getDataCommand = new RelayCommand(() =>
                    {
                        if (IsFirstTimeLoaded)
                        {
                            GetGroupsFromStorage();
                            if (Groups == null)
                                GetGroupsFromWebService();
                            IsFirstTimeLoaded = false;
                        }
                    });
                return getDataCommand;
            }
        }

        private RelayCommand copyCodeToClipboardCommand;
        public RelayCommand CopyCodeToClipboardCommand
        {
            get
            {
                return copyCodeToClipboardCommand ?? (copyCodeToClipboardCommand = new RelayCommand(() =>
                {
                    DataPackage dataPackage = new DataPackage();
                    dataPackage.RequestedOperation = DataPackageOperation.Copy;
                    dataPackage.SetText(CodeViewSnippet.Code);
#if WINDOWS_APP
                    Clipboard.SetContent(dataPackage);
#endif
                }));
            }
        }

        private RelayCommand getNextSnippetsCommand;
        public RelayCommand GetNextSnippetsCommand
        {
            get
            {
                return getNextSnippetsCommand ?? (getNextSnippetsCommand = new RelayCommand(() =>
                {
                    GetNextSnippets();
                }));
            }
        }

        private RelayCommand searchCommand;
        public RelayCommand SearchCommand
        {
            get
            {
                return searchCommand ?? (searchCommand = new RelayCommand(() =>
                {
                    IsBusy = true;
                    GetSearchResults();
                }, () => { return SearchTerm != null && SearchTerm.Length >= 3; }));
            }
        }

        private RelayCommand incrementFontSizeCommand;
        public RelayCommand IncrementFontSizeCommand
        {
            get
            {
                return incrementFontSizeCommand ?? (incrementFontSizeCommand = new RelayCommand(() =>
                {
                    codeFontIndex++;
                    CodeFontSize = fontSizes[codeFontIndex];
                    IncrementFontSizeCommand.RaiseCanExecuteChanged();
                }, () => { return codeFontIndex < fontSizes.Length - 1; }));
            }
        }

        private RelayCommand decrementFontSizeCommand;
        public RelayCommand DecrementFontSizeCommand
        {
            get
            {
                return decrementFontSizeCommand ?? (decrementFontSizeCommand = new RelayCommand(() =>
                {
                    codeFontIndex--;
                    CodeFontSize = fontSizes[codeFontIndex];
                    DecrementFontSizeCommand.RaiseCanExecuteChanged();
                }, () => { return codeFontIndex > 0; }));
            }
        }
        #endregion

        #region AsyncMethods
        private async void GetGroupsFromStorage()
        {
            Groups = await storage.GetRecent();
            IsBusy = false;
        }
        private async void GetGroupsFromWebService()
        {
            Groups = await webService.GetGroupsFull();
            storage.WriteRecent(Groups);
            IsBusy = false;
        }

        private async void GetCodeViewSnippet()
        {
            CodeViewSnippet = await webService.GetSnippet(CodeViewSnippet.GroupId, CodeViewSnippet.Id);
            IsBusy = false;
        }

        private async void GetNextSnippets()
        {
            var newSnippets = await webService.GetNextSnippets(SelectedCodeGroup.GroupId, selectedCodeGroup.LastSnippetId, 2);
            foreach (CodeSnippet cs in newSnippets)
            {
                SelectedCodeGroup.Snippets.Add(cs);
            }
            if (SelectedCodeGroup.Snippets.Count > 0)
                SelectedCodeGroup.LastSnippetId = SelectedCodeGroup.Snippets[SelectedCodeGroup.Snippets.Count - 1].Id;
            RaisePropertyChanged("SelectedCodeGroup");
            IsBusy = false;
        }


        private async void GetSearchResults()
        {
            SearchResults = await webService.SearchSnippets(SearchTerm);
            IsBusy = false;
        }
        #endregion
    }
}
